package com.aps.algorithm.heuristic.genetic.dto;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;

/**
 * 时间区间类
 * 
 * 在APS排程系统中，设备的时间占用情况需要被精确跟踪。
 * 该类用于表示设备在某个时间段内被占用的情况。
 * 
 * 业务场景：
 * - 设备M1在2024-06-01 08:00到2024-06-01 10:30被工序J1-1占用
 * - 设备M1在2024-06-01 10:30到2024-06-01 14:20被工序J2-1占用
 * - 通过维护这些时间区间，可以检测设备冲突和计算设备利用率
 * 
 * @author APS System
 * @version 1.0
 */
public class Interval {
    
    /** 时间格式化器 */
    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm");
    
    /** 时间区间的开始时间 */
    private LocalDateTime start;
    
    /** 时间区间的结束时间 */
    private LocalDateTime end;
    
    /**
     * 构造函数
     * 
     * @param start 开始时间
     * @param end 结束时间
     */
    public Interval(LocalDateTime start, LocalDateTime end) {
        if (start.isAfter(end)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }
        this.start = start;
        this.end = end;
    }
    
    // Getter和Setter方法
    
    /**
     * 获取开始时间
     * 
     * @return 开始时间
     */
    public LocalDateTime getStart() {
        return start;
    }
    
    /**
     * 设置开始时间
     * 
     * @param start 开始时间
     */
    public void setStart(LocalDateTime start) {
        if (start.isAfter(this.end)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }
        this.start = start;
    }
    
    /**
     * 获取结束时间
     * 
     * @return 结束时间
     */
    public LocalDateTime getEnd() {
        return end;
    }
    
    /**
     * 设置结束时间
     * 
     * @param end 结束时间
     */
    public void setEnd(LocalDateTime end) {
        if (this.start.isAfter(end)) {
            throw new IllegalArgumentException("开始时间不能晚于结束时间");
        }
        this.end = end;
    }
    
    /**
     * 计算时间区间的持续时长（分钟）
     * 
     * @return 持续时长（分钟）
     */
    public long getDurationInMinutes() {
        return java.time.Duration.between(start, end).toMinutes();
    }
    
    /**
     * 检查该时间区间是否与另一个时间区间有重叠
     * 
     * 重叠判断逻辑：
     * - 如果一个区间的结束时间早于另一个区间的开始时间，则无重叠
     * - 如果一个区间的开始时间晚于另一个区间的结束时间，则无重叠
     * - 其他情况都存在重叠
     * 
     * @param other 另一个时间区间
     * @return 如果有重叠返回true，否则返回false
     */
    public boolean overlaps(Interval other) {
        return !(this.end.isBefore(other.start) || this.start.isAfter(other.end));
    }
    
    /**
     * 检查指定时间点是否在该区间内
     * 
     * @param time 要检查的时间点
     * @return 如果时间点在区间内（包含边界）返回true，否则返回false
     */
    public boolean contains(LocalDateTime time) {
        return !time.isBefore(start) && !time.isAfter(end);
    }
    
    /**
     * 检查该区间是否完全包含另一个区间
     * 
     * @param other 另一个时间区间
     * @return 如果完全包含返回true，否则返回false
     */
    public boolean contains(Interval other) {
        return !other.start.isBefore(this.start) && !other.end.isAfter(this.end);
    }
    
    /**
     * 计算与另一个区间的重叠时长（分钟）
     * 
     * @param other 另一个时间区间
     * @return 重叠时长（分钟），如果无重叠返回0
     */
    public long getOverlapDurationInMinutes(Interval other) {
        if (!overlaps(other)) {
            return 0;
        }
        
        LocalDateTime overlapStart = this.start.isAfter(other.start) ? this.start : other.start;
        LocalDateTime overlapEnd = this.end.isBefore(other.end) ? this.end : other.end;
        
        return java.time.Duration.between(overlapStart, overlapEnd).toMinutes();
    }
    
    /**
     * toString方法，便于调试和日志输出
     * 
     * @return 格式化的字符串表示
     */
    @Override
    public String toString() {
        return String.format("[%s ~ %s] (%d分钟)", 
                start.format(formatter), 
                end.format(formatter),
                getDurationInMinutes());
    }
    
    /**
     * equals方法，用于比较两个时间区间是否相等
     * 
     * @param obj 要比较的对象
     * @return 如果相等返回true，否则返回false
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        
        Interval interval = (Interval) obj;
        return start.equals(interval.start) && end.equals(interval.end);
    }
    
    /**
     * hashCode方法，用于散列集合
     * 
     * @return 散列值
     */
    @Override
    public int hashCode() {
        return java.util.Objects.hash(start, end);
    }
}
